package at.fhhagenberg.hydrac.java.sample.ast;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PostfixExpression.Operator;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

import at.fhhagenberg.hydrac.java.sample.ast.codegen.builder.AstBuilder;
import at.fhhagenberg.hydrac.java.sample.ast.codegen.builder.ClassBuilder;
import at.fhhagenberg.hydrac.java.sample.ast.codegen.builder.MethodBuilder;


public class CodeGenMinMax {

	private static AST ast;
	private static AstBuilder builder;

	public static void main(String[] args) {

		builder = new AstBuilder();

		ClassBuilder classBuilder = builder.createClass("com.google.code", "MinMax");
		ast = classBuilder.getAst();

		MethodBuilder methodBuilder = classBuilder.addMainMethod();

		ArrayCreation arrayCreation = builder.getNumberArrayInitializer(builder.intType(), "1", "3", "7", "9", "3", "1");

		methodBuilder.addVariableDeclaration("argc", ast.newArrayType(builder.intType()), arrayCreation);

		methodBuilder.addVariableDeclaration("min", builder.intType(),
				ast.newQualifiedName(ast.newSimpleName("Integer"), ast.newSimpleName("MAX_VALUE")));
		methodBuilder.addVariableDeclaration("max", builder.intType(),
				ast.newQualifiedName(ast.newSimpleName("Integer"), ast.newSimpleName("MIN_VALUE")));

		VariableDeclarationFragment varDecl = ast.newVariableDeclarationFragment();
		varDecl.setName(ast.newSimpleName("i"));
		varDecl.setInitializer(ast.newNumberLiteral("0"));

		VariableDeclarationExpression varDeclExpr = ast.newVariableDeclarationExpression(varDecl);
		varDeclExpr.setType(builder.intType());

		ForStatement forStmt = ast.newForStatement();
		forStmt.initializers().add(varDeclExpr);

		PostfixExpression updatesExpr = ast.newPostfixExpression();
		updatesExpr.setOperand(ast.newSimpleName("i"));
		updatesExpr.setOperator(Operator.INCREMENT);
		forStmt.updaters().add(updatesExpr);

		InfixExpression expr = ast.newInfixExpression();
		expr.setLeftOperand(ast.newSimpleName("i"));
		expr.setOperator(org.eclipse.jdt.core.dom.InfixExpression.Operator.LESS);
		expr.setRightOperand(ast.newQualifiedName(ast.newSimpleName("argc"), ast.newSimpleName("length")));
		forStmt.setExpression(expr);
		methodBuilder.addStatement(forStmt);

		// for stmt body
		forStmt.setBody(forBody());

		// sysout

		MethodInvocation methodInvocation = ast.newMethodInvocation();
		methodInvocation.setName(ast.newSimpleName("println"));
		methodInvocation.setExpression(ast.newQualifiedName(ast.newSimpleName("System"), ast.newSimpleName("out")));

		InfixExpression ouputExpr = ast.newInfixExpression();
		ouputExpr.setLeftOperand(builder.stringLiteral("maximum = "));
		ouputExpr.setOperator(org.eclipse.jdt.core.dom.InfixExpression.Operator.PLUS);
		ouputExpr.setRightOperand(ast.newSimpleName("max"));

		ouputExpr.extendedOperands().add(builder.stringLiteral(" , minimum = "));
		ouputExpr.extendedOperands().add(ast.newSimpleName("min"));

		methodInvocation.arguments().add(ouputExpr);

		methodBuilder.addStatement(ast.newExpressionStatement(methodInvocation));

		System.out.println(classBuilder);
	}

	private static Block forBody() {
		Block block = ast.newBlock();

		VariableDeclarationFragment varDecl = ast.newVariableDeclarationFragment();
		varDecl.setName(ast.newSimpleName("val"));

		ArrayAccess arrayAccess = ast.newArrayAccess();
		arrayAccess.setIndex(ast.newSimpleName("i"));
		arrayAccess.setArray(ast.newSimpleName("argc"));
		varDecl.setInitializer(arrayAccess);

		VariableDeclarationStatement varDeclStmt = ast.newVariableDeclarationStatement(varDecl);
		varDeclStmt.setType(builder.intType());
		block.statements().add(varDeclStmt);

		// if max
		InfixExpression maxExpression = ast.newInfixExpression();
		maxExpression.setLeftOperand(ast.newSimpleName("val"));
		maxExpression.setOperator(org.eclipse.jdt.core.dom.InfixExpression.Operator.GREATER);
		maxExpression.setRightOperand(ast.newSimpleName("max"));

		IfStatement maxIfStmt = ast.newIfStatement();
		maxIfStmt.setExpression(maxExpression);
		block.statements().add(maxIfStmt);

		Block maxBlock = ast.newBlock();
		Assignment maxAssignment = ast.newAssignment();
		maxAssignment.setLeftHandSide(ast.newSimpleName("max"));
		maxAssignment.setOperator(org.eclipse.jdt.core.dom.Assignment.Operator.ASSIGN);
		maxAssignment.setRightHandSide(ast.newSimpleName("val"));

		maxBlock.statements().add(ast.newExpressionStatement(maxAssignment));
		maxIfStmt.setThenStatement(maxBlock);

		// if min
		InfixExpression minExpression = ast.newInfixExpression();
		minExpression.setLeftOperand(ast.newSimpleName("val"));
		minExpression.setOperator(org.eclipse.jdt.core.dom.InfixExpression.Operator.LESS);
		minExpression.setRightOperand(ast.newSimpleName("min"));

		IfStatement minIfStmt = ast.newIfStatement();
		minIfStmt.setExpression(minExpression);
		block.statements().add(minIfStmt);

		Block minBlock = ast.newBlock();
		Assignment minAssignment = ast.newAssignment();
		minAssignment.setLeftHandSide(ast.newSimpleName("min"));
		minAssignment.setOperator(org.eclipse.jdt.core.dom.Assignment.Operator.ASSIGN);
		minAssignment.setRightHandSide(ast.newSimpleName("val"));

		minBlock.statements().add(ast.newExpressionStatement(minAssignment));
		minIfStmt.setThenStatement(minBlock);

		return block;
	}
}
